package com.geor.gcv.core.mat;

import java.util.ArrayList;
import java.util.List;

import org.nutz.log.Loggers;
import org.opencv.core.Mat;
import org.slf4j.Logger;

import com.geor.gcv.core.model.Cluster;
import com.geor.gcv.core.model.Node;
import com.geor.gcv.core.util.DataTool;

/**
 * 连通域接口默认实现
 * 
 * @author geor.lusongnan
 *
 */
public class DomainConnectorDefault implements DomainConnector {
	Logger log = Loggers.get();
	Mat src;

	@Override
	public List<Domain> get(Mat mat, int pex) {
		this.src = mat;
		final Integer[][] pex_level = new Integer[src.rows()][src.cols()];
		new ImageOperator(src) {
			@Override
			public void operate(int row, int col, double[] pex) {
				pex_level[row][col] = (int) pex[0];
			}
		};

		List<Cluster> clusters = genClusters(pex, pex_level);
		List<Domain> domains = merge(clusters);
		return domains;
	}

	/**
	 * 生成连通域团
	 * 
	 * @param level
	 * @param pex_level
	 * @return
	 */
	private List<Cluster> genClusters(int level, Integer[][] pex_level) {

		int index = 0;
		// 每行的团
		List<List<Cluster>> listRuns = new ArrayList<List<Cluster>>();
		// 获得第一层的团
		int start = 0;
		int end = 0;
		List<Cluster> runs = new ArrayList<Cluster>();
		for (int col = 0; col < src.cols(); col++) {
			int value = pex_level[0][col];
			if (value == level) {
				start = col;
				end = getEnd(start, 0, level, pex_level);
				col = end;
				Cluster run = new Cluster(start, end, index, 0, level);
				run.tags.add(++index);
				runs.add(run);
			}
		}
		listRuns.add(runs);
		// 开始生成后面的团
		for (int row = 1; row < src.rows(); row++) {
			// 取最后一个团
			List<Cluster> finalRuns = listRuns.get(listRuns.size() - 1);
			// 存放当前需要生成的团
			List<Cluster> newRuns = new ArrayList<Cluster>();
			for (int col = 0; col < src.cols(); col++) {
				// 该像素的等级
				int value = pex_level[row][col];
				// 根据等级生成团
				if (value == level) {
					start = col;
					end = getEnd(start, row, level, pex_level);
					col = end;
					Cluster run = new Cluster(start, end, 0, row, level);
					boolean flag = false;
					// 给团run标记
					for (int i = 0; i < finalRuns.size(); i++) {
						Cluster run1 = finalRuns.get(i);
						if ((run.min <= run1.max + 1 && run.min >= run1.min - 1)
								|| (run.max <= run1.max + 1 && run.max >= run1.min - 1)
								|| (run1.min >= run.min - 1 && run1.min <= run.max + 1)
								|| (run1.max >= run.min - 1 && run1.max <= run.max + 1)) {
							for (int tag : run1.tags) {
								if (run.tags.contains(tag)) {
									continue;
								}
								run.tags.add(tag);
							}
							flag = true;
						}
					}
					if (!flag) {
						run.tags.add(++index);
					}
					newRuns.add(run);
				}
			}
			// 添加到团集合中
			listRuns.add(newRuns);
		}

		// 保存等值对
		List<List<Integer>> listLists = new ArrayList<List<Integer>>();
		// 保存
		for (int i = 0; i < listRuns.size(); i++) {
			for (int j = 0; j < listRuns.get(i).size(); j++) {
				Cluster temp = listRuns.get(i).get(j);

				if (temp.tags.size() >= 2) {
					temp.tag = temp.tags.get(DataTool.getListMinIndex(temp.tags));
					if (listLists.size() == 0) {
						listLists.add(temp.tags);
					} else {
						// 过滤一下listLists
						boolean flag = false;
						for (int n = 0; n < listLists.size(); n++) {
							for (int m = 0; m < listLists.get(n).size(); m++) {
								if (temp.tags.contains(listLists.get(n).get(m))) {
									flag = true;
									for (int tag : temp.tags) {
										if (!listLists.get(n).contains(tag)) {
											listLists.get(n).add(tag);
										}
									}
								}
							}
							if (flag) {
								break;
							}
						}
						if (!flag)
							listLists.add(temp.tags);
					}
				}

				if (temp.tags.size() == 1) {
					temp.tag = temp.tags.get(0);
				}
			}
		}

		// 等值对
		for (int i = 0; i < listLists.size(); i++) {
			int min = listLists.get(i).get(DataTool.getListMinIndex(listLists.get(i)));
			for (int j = 0; j < listLists.size(); j++) {
				for (int n = 0; n < listRuns.size(); n++) {
					for (int m = 0; m < listRuns.get(n).size(); m++) {
						if (listLists.get(i).contains(listRuns.get(n).get(m).tag)) {
							listRuns.get(n).get(m).tag = min;
						}
					}
				}
			}
		}
		List<Cluster> temps = new ArrayList<Cluster>();
		for (int i = 0; i < listRuns.size(); i++) {
			for (int j = 0; j < listRuns.get(i).size(); j++) {
				temps.add(listRuns.get(i).get(j));
			}
		}
		return temps;
	}

	/** 搜索团的结束位置 */
	private int getEnd(int col, int row, int level, Integer[][] pex_level) {
		++col;
		if (col >= pex_level[row].length) {
			return pex_level[row].length - 1;
		}
		if (col < pex_level[row].length && pex_level[row][col] != level) {
			return --col;
		}
		return getEnd(col, row, level, pex_level);
	}

	/**
	 * 合并连通域
	 * 
	 * @param clusters
	 * @return
	 */
	public List<Domain> merge(List<Cluster> clusters) {
		// 辅助作用
		List<Integer> lists = new ArrayList<Integer>();
		// 每行的团
		List<List<Cluster>> listRuns = new ArrayList<List<Cluster>>();
		// 开始合并团
		for (int i = 0; i < clusters.size(); i++) {
			if (lists.contains(i)) {
				continue;
			}
			lists.add(i);
			List<Cluster> temps = new ArrayList<Cluster>();

			Cluster run1 = clusters.get(i);
			temps.add(run1);
			for (int j = i + 1; j < clusters.size(); j++) {
				if (lists.contains(j))
					continue;
				Cluster run2 = clusters.get(j);

				for (int n = 0; n < run1.tags.size(); n++) {
					if (run2.tag == run1.tag) {
						lists.add(j);
						temps.add(run2);
					}
				}
			}
			listRuns.add(temps);
		}

		// 合并团结束!
		int sum = 0;

		for (int i = 0; i < listRuns.size(); i++) {
			sum += listRuns.get(i).size();
		}

		if (sum == clusters.size()) {
			log.trace("合并团成功!");
		} else {
			log.trace("合并失败部分团丢失!");
		}
		// 连通域
		List<Domain> surfaces = new ArrayList<Domain>();
		for (int i = 0; i < listRuns.size(); i++) {
			List<Cluster> tempRuns = listRuns.get(i);
			DomainImpl surface = new DomainImpl();
			for (int j = 0; j < tempRuns.size(); j++) {
				Cluster run = tempRuns.get(j);
				for (int m = run.min; m <= run.max; m++) {
					surface.nodes.add(new Node(run.row, m, run.level, src.get(run.row, m)[0]));
				}
			}
			if (surface.nodes.size() != 0)
				surfaces.add(surface);
		}
		return surfaces;
	}

}
